package com.benefm.multipar.pad.util;

public class BfmZipUtils {
    // 模拟正弦波数据
    final static short SIN_DATA[] = {
            0x7FF, 0x82, 0x866, 0x899, 0x8CC, 0x900, 0x933, 0x965, 0x998, 0x9CA, 0x9FC, 0xA2E, 0xA5F, 0xA90, 0xAC1, 0xAF1
            , 0xB20, 0xB4F, 0xB7E, 0xBAC, 0xBD9, 0xC06, 0xC32, 0xC5E, 0xC88, 0xCB2, 0xCDC, 0xD04, 0xD2C, 0xD53, 0xD79, 0xD9E
            , 0xDC2, 0xDE5, 0xE07, 0xE29, 0xE49, 0xE68, 0xE86, 0xEA4, 0xEC0, 0xEDB, 0xEF5, 0xF0D, 0xF25, 0xF3C, 0xF51, 0xF65
            , 0xF78, 0xF8A, 0xF9A, 0xFAA, 0xFB8, 0xFC4, 0xFD0, 0xFDA, 0xFE3, 0xFEB, 0xFF1, 0xFF7, 0xFFA, 0xFFD, 0xFFE, 0xFFE
            , 0xFFD, 0xFFA, 0xFF7, 0xFF1, 0xFEB, 0xFE3, 0xFDA, 0xFD0, 0xFC4, 0xFB8, 0xFAA, 0xF9A, 0xF8A, 0xF78, 0xF65, 0xF51
            , 0xF3C, 0xF25, 0xF0D, 0xEF5, 0xEDB, 0xEC0, 0xEA4, 0xE86, 0xE68, 0xE49, 0xE29, 0xE07, 0xDE5, 0xDC2, 0xD9E, 0xD79
            , 0xD53, 0xD2C, 0xD04, 0xCDC, 0xCB2, 0xC88, 0xC5E, 0xC32, 0xC06, 0xBD9, 0xBAC, 0xB7E, 0xB4F, 0xB20, 0xAF1, 0xAC1
            , 0xA90, 0xA5F, 0xA2E, 0x9FC, 0x9CA, 0x998, 0x965, 0x933, 0x900, 0x8CC, 0x899, 0x866, 0x832, 0x7FF, 0x7CC, 0x798
            , 0x765, 0x732, 0x6FE, 0x6CB, 0x699, 0x666, 0x634, 0x602, 0x5D0, 0x59F, 0x56E, 0x53D, 0x50D, 0x4DE, 0x4AF, 0x480
            , 0x452, 0x425, 0x3F8, 0x3CC, 0x3A0, 0x376, 0x34C, 0x322, 0x2FA, 0x2D2, 0x2AB, 0x285, 0x260, 0x23C, 0x219, 0x1F7
            , 0x1D5, 0x1B5, 0x196, 0x178, 0x15A, 0x13E, 0x123, 0x109, 0x0F1, 0x0D9, 0x0C2, 0x0AD, 0x099, 0x086, 0x074, 0x064
            , 0x054, 0x046, 0x03A, 0x02E, 0x024, 0x01B, 0x013, 0x00D, 0x007, 0x004, 0x001, 0x000, 0x000, 0x001, 0x004, 0x007
            , 0x00D, 0x013, 0x01B, 0x024, 0x02E, 0x03A, 0x046, 0x054, 0x064, 0x074, 0x086, 0x099, 0x0AD, 0x0C2, 0x0D9, 0x0F0
            , 0x109, 0x123, 0x13E, 0x15A, 0x178, 0x196, 0x1B5, 0x1D5, 0x1F7, 0x219, 0x23C, 0x260, 0x285, 0x2AB, 0x2D2, 0x2FA
            , 0x322, 0x34B, 0x375, 0x3A0, 0x3CC, 0x3F8, 0x425, 0x452, 0x480, 0x4AF, 0x4DE, 0x50D, 0x53D, 0x56E, 0x59F, 0x5D0
            , 0x602, 0x634, 0x666, 0x699, 0x6CB, 0x6FE, 0x731, 0x765, 0x798, 0x7CC
    };


    /**
     * @param pSrcBuf     原始数据
     * @param leadNum     导联个数
     * @param pZipDataBuf 压缩后保存数据缓冲区，建议其长度为nSrcLen的3倍
     * @return 压缩后数据总长度
     * @brief compress  压缩
     */
    public static int compress(short[] pSrcBuf, int leadNum, byte[] pZipDataBuf) {
        int i = 0, j = 0;
        int index = 0;
        int offset = 0;
        short value = 0;
        short diff = 0;
        int nDataCntPerLead = 0;
        short maxDiff = -1;
        int nSrcLen = 0;
        int nDestLen = 0;
        byte[] xTemp;
        do {
            if (null == pSrcBuf) {
                break;
            }
            if (0 >= pSrcBuf.length) {
                break;
            }
            if (0 >= leadNum) {
                break;
            }
            nSrcLen = pSrcBuf.length;
            if (nSrcLen < leadNum) {
                break;
            }
            if (0 != (nSrcLen % leadNum)) {
                break;
            }
            if (null == pZipDataBuf) {
                break;
            }
            nDestLen = pZipDataBuf.length;
            nDataCntPerLead = nSrcLen / leadNum;
            index = 0;
            pZipDataBuf[index++] = (byte) leadNum;
            for (i = 0; i < leadNum; i++) {
                xTemp = DataUtil.short2ByteArray(pSrcBuf[i], false);
                System.arraycopy(xTemp, 0, pZipDataBuf, index, xTemp.length);
                index += xTemp.length;
            }
            if (nDestLen + leadNum < nSrcLen) {
                break;
            }

            for (i = 1; i < nDataCntPerLead; i++) {
                for (j = 0; j < leadNum; j++) {
                    offset = i * leadNum + j;
                    value = pSrcBuf[offset - leadNum];
                    diff = (short) (pSrcBuf[offset] - value);
                    if (maxDiff < diff) {
                        maxDiff = diff;
                    }
                    if ((-128 > diff) || (127 < diff)) {
                        if ((index + 4) >= nDestLen) {
                            index = -1;  // 内存不足
                            break;
                        }
                        pZipDataBuf[index++] = 0x5A;
                        pZipDataBuf[index++] = (byte) 0xA5;
                        pZipDataBuf[index++] = (byte) ((pSrcBuf[offset] & 0xff) >> 0);
                        pZipDataBuf[index++] = (byte) ((pSrcBuf[offset] & 0xff00) >> 8);
                    } else {
                        if ((index + 1) >= nDestLen) {
                            index = -1; // 内存不足
                            break;
                        }
                        pZipDataBuf[index++] = (byte) diff;
                    }
                }

                if (0 > index) {
                    index = 0;   // 内存不足
                    break;
                }
            }
        } while (false);
        return index;
    }


    /**
     * @param pZipDataBuf：压缩后的数据缓冲区
     * @param length：压缩后的数据缓冲区长度
     * @param pUnZipDataBuf：存放压缩后的数据缓冲区，建议其长度不小于length
     * @return 解压后的数据长度
     * @brief decompress 解压数据
     */
    public static int decompress(byte[] pZipDataBuf, int length, short[] pUnZipDataBuf) {
        int i = 0;
        int j = 0;
        int index = 0;
        int offset = 0;
        int leadIndex = 0;
        char byValue = 0;
        short ssValue = 0;
        short ssData = 0;
        short ssTemp = 0;
        int leadNum = 0;
        int nUnzipDataLength = 0;
        do {
            if (null == pZipDataBuf) {
                break;
            }
            if (1 >= length) {
                break;
            }
            if (0 > pZipDataBuf[leadNum]) {
                leadNum = pZipDataBuf[j++] + 256;
            } else {
                leadNum = pZipDataBuf[j++];
            }
            if (0 >= leadNum) {
                break;
            }
            if (leadNum > length) {
                break;
            }
            if (null == pUnZipDataBuf) {
                break;
            }
            nUnzipDataLength = pUnZipDataBuf.length;
            if (0 >= nUnzipDataLength) {
                break;
            }
            for (i = 0; i < leadNum; i++) {
                pUnZipDataBuf[i] = DataUtil.byteArray2short(pZipDataBuf, j, false);
                j += 2;
            }
            for (; j < length; j++) {
                if ((i + 1) > nUnzipDataLength) {
                    i = 0;
                    break;
                }
                if (((j + 1) < length) && (0x5A == pZipDataBuf[j]) && ((byte) 0xA5 == pZipDataBuf[j + 1])) {
                    j += 2;
                    ssData = DataUtil.byteArray2short(pZipDataBuf, j, false);
                    pUnZipDataBuf[i++] = ssData;
                    j += 1;    // for中还有一次j++，所以此次只加1
                } else {
                    offset = i - leadNum;
                    ssValue = pUnZipDataBuf[offset];
                    ssTemp = (short) (ssValue + pZipDataBuf[j]);
                    pUnZipDataBuf[i++] = ssTemp;
                }
            }
        } while (false);
        return i;
    }

    public static short getShort(byte[] b) {
        return (short) (((b[1] << 8) | b[0] & 0xff));
    }


//    public static void main(String args[]) throws Exception {
//        testCompress();
//    }

    public static void testCompress() {

        int i, j;
        int offset = 0;
        int leadNum = 3;       // 模拟12个导联
        int nSrcDataLen = SIN_DATA.length * leadNum;
        int nDestDataLen = nSrcDataLen * 3;
        short[] pSrcData = new short[nSrcDataLen];

        int nZipDataLength = 0;

        String strSrcFileName = "D:/sin_src.dat";
        String strZipFileName = "D:/sin_zip.dat";

        // 模拟生成12导联数据
        for (i = 0, offset = 0; i < SIN_DATA.length; i++) {
            for (j = 0; j < leadNum; j++) {
                pSrcData[offset++] = (short) (SIN_DATA[i] * 2.45 + j * 10);
            }
        }

        // 1.压缩
        byte[] pZipData = new byte[SIN_DATA.length * leadNum * 3];
        int zipLength = compress(pSrcData, leadNum, pZipData);

        // 2.解压：验证内存
        short[] pUnzipData = new short[SIN_DATA.length * leadNum];
        int unzipLength = decompress(pZipData, zipLength, pUnzipData);

//        // 2.解压：验证文件
//        File file = new File(strZipFileName);
//        try (InputStream in = new FileInputStream(file)){
//
//
//            byte[] xZipData = new byte[in.available()];
//            in.read(xZipData);
//            int nUnzipLength = decompress(xZipData, xZipData.length, pUnzipData);
//            for (i = 0; i < nSrcDataLen; i++) {
//                if (pSrcData[i] != pUnzipData[i]) {
//                    break;
//                }
//            }
//        } catch (FileNotFoundException e) {
//            e.printStackTrace();
//        } catch (IOException e) {
//            e.printStackTrace();
//        }

        // 3.验证解压后数据与原始是否一致
        for (i = 0; i < nSrcDataLen; i++) {
            if (pSrcData[i] != pUnzipData[i]) {
                System.out.println("error " + i);
                break;
            }
        }
        if (i == nSrcDataLen) {
            System.out.println("matches");
        }


        pSrcData = null;

        pUnzipData = null;

        pZipData = null;
    }
}
